package edu.gmu.projects.fireresponder.fusionengine;

import edu.gmu.projects.fireresponder.xml.alerts.Alert;
import edu.gmu.projects.fireresponder.xml.alerts.FirstResponderAlert;
import edu.gmu.projects.fireresponder.xml.alerts.MotionDetectorAlert;

public class PresenceAnchorPoint extends AnchorPoint {

	// maximum likelihood of a single location accurately representing an event
	public static final double MAX_SINGLE_POINT_PROBABILITY = 1;
	public static final double NUMBER_OF_ALERT_SCORE_FOR_FULL_CONFIDENCE = 8;
	public static final double EXPOTENTIAL_GROWTH_RATE = 1;
	// 1 = linear, greater than 1, newer are more heavily weighted
	public static final double WEIGHT_OF_RECENCY = 2;  
	// Max age we will consider an alert
	public static final long OLDEST_NOTEWORTHY_ALERT = 60000; // 1 minutes

	protected long lastAlertTime;

	public boolean addAlert(Alert alert) {
		boolean validAlert = false;
		if(alert instanceof MotionDetectorAlert) {
			addEvent(alert);
			lastAlertTime = alert.getTime().getTimeInMillis();	
			updatePointProbability();
			validAlert = true;
		} else if(alert instanceof FirstResponderAlert) {
			FirstResponderAlert fra = (FirstResponderAlert) alert;
			for(Alert embeddedAlert : fra.getEmbeddedAlerts()) {
				if(embeddedAlert instanceof MotionDetectorAlert) {
					lastAlertTime = alert.getTime().getTimeInMillis();	
					addEvent(embeddedAlert, NUMBER_OF_ALERT_SCORE_FOR_FULL_CONFIDENCE, true);
					validAlert = true;
				}
			}
		}
		return validAlert;
	}

	public static boolean isValidAlert(Alert alert) {
		boolean validAlert = false;
		if(alert instanceof MotionDetectorAlert) {
			validAlert = true;
		} else if(alert instanceof FirstResponderAlert) {
			FirstResponderAlert fra = (FirstResponderAlert) alert;
			for(Alert embeddedAlert : fra.getEmbeddedAlerts()) {
				if(embeddedAlert instanceof MotionDetectorAlert) {
					validAlert = true;
					break;
				}
			}
		}
		return validAlert;
	}
	
	protected long lastAlertTime() {
		return lastAlertTime;
	}
	
	protected boolean isActive() {
		long delta = System.currentTimeMillis() - lastAlertTime;
		return delta < OLDEST_NOTEWORTHY_ALERT;
	}

	protected void updatePointProbability() {
		long now = System.currentTimeMillis();
		long acceptedAlertTime = now - OLDEST_NOTEWORTHY_ALERT;
		double validAlertScore = 0;

		boolean ignoreCap = false;
		for(Event event : events) {
			if(event.timeStamp > acceptedAlertTime) {
				double ageWeight = Math.pow(1.0 - (((double)(now - event.timeStamp)) 
						/ ((double)OLDEST_NOTEWORTHY_ALERT)), WEIGHT_OF_RECENCY);
				
				validAlertScore += (ageWeight * event.score);
				if(event.overridesCap) {
					ignoreCap = true;
				}
			} else {
				break;  // alerts are in order, most recent to oldest
			}
		}
		
		double rate = 1 / NUMBER_OF_ALERT_SCORE_FOR_FULL_CONFIDENCE;
		
		double newProbability = Math.pow(rate * ((double) validAlertScore), EXPOTENTIAL_GROWTH_RATE);
		if(newProbability > MAX_SINGLE_POINT_PROBABILITY && ! ignoreCap) {
			probability = MAX_SINGLE_POINT_PROBABILITY;
		} else if(newProbability > 1) {
			probability = 1;
		} else {
			probability = newProbability;
		}
	}

}
